use thiserror::Error;
use actix_web::http::StatusCode;

/// Policy operation errors
#[derive(Error, Debug, Clone)]
pub enum PolicyError {
    /// Incorrect input parameter format
    #[error("Incorrect formatting of input parameters: {0}")]
    IncorrectFormatError(String),

    /// Missing required parameters
    #[error("Required parameters are missing: {0}")]
    MissingRequiredParamError(String),

    /// Policy file not found
    #[error("Policy not found: {0}")]
    PolicyNotFoundError(String),

    /// Policy file signature verification failed
    #[error("Failure to verify signature of policy file: {0}")]
    PolicySignatureVerificationError(String),

    /// Syntax error occurred when matching sample output with policy
    #[error("Syntax error when sample output matches policy: {0}")]
    PolicyMatchSyntaxError(String),

    /// Failed to verify signature of policy retrieved from database
    #[error("Failed to validate the policy signature taken out of the database: {0}")]
    DatabasePolicySignatureError(String),

    /// Database operation failed
    #[error("Database operation failed: {0}")]
    DatabaseOperationError(String),

    /// Database connection failed
    #[error("Database connection failed: {0}")]
    DatabaseConnectionError(String),

    /// Internal error
    #[error("Internal error: {0}")]
    InternalError(String),

    /// Invalid policy content
    #[error("Invalid policy content: {0}")]
    InvalidPolicyContent(String),

    // Policy signature failure
    #[error("Policy signature failure: {0}")]
    PolicySignatureFailure(String),

    // Single user policy file creation limit reached
    #[error("Strategy has reached its limit and cannot be created: {0}")]
    PolicyLimitReached(String),

    // Policy content size limit reached
    #[error("Strategy content is greater than the cap: {0}")]
    PolicyContentSizeLimitReached(String),
}

impl PolicyError {
    /// Get corresponding HTTP status code
    pub fn status_code(&self) -> StatusCode {
        match self {
            PolicyError::IncorrectFormatError(_) => StatusCode::BAD_REQUEST,
            PolicyError::PolicyNotFoundError(_) => StatusCode::BAD_REQUEST,
            PolicyError::MissingRequiredParamError(_) => StatusCode::BAD_REQUEST,
            PolicyError::PolicySignatureVerificationError(_) => StatusCode::BAD_REQUEST,
            PolicyError::PolicyMatchSyntaxError(_) => StatusCode::BAD_REQUEST,
            PolicyError::DatabasePolicySignatureError(_) => StatusCode::INTERNAL_SERVER_ERROR,
            PolicyError::DatabaseOperationError(_) => StatusCode::INTERNAL_SERVER_ERROR,
            PolicyError::DatabaseConnectionError(_) => StatusCode::INTERNAL_SERVER_ERROR,
            PolicyError::InternalError(_) => StatusCode::INTERNAL_SERVER_ERROR,
            PolicyError::InvalidPolicyContent(_) => StatusCode::BAD_REQUEST,
            PolicyError::PolicySignatureFailure(_) => StatusCode::INTERNAL_SERVER_ERROR,
            PolicyError::PolicyLimitReached(_) => StatusCode::BAD_REQUEST,
            PolicyError::PolicyContentSizeLimitReached(_) => StatusCode::BAD_REQUEST,
        }
    }

    /// Get error message
    pub fn message(&self) -> String {
        self.to_string()
    }
}

/// Convert from other error types to PolicyError
impl From<String> for PolicyError {
    fn from(err: String) -> Self {
        PolicyError::InternalError(err)
    }
}

impl From<&str> for PolicyError {
    fn from(err: &str) -> Self {
        PolicyError::InternalError(err.to_string())
    }
}

impl From<std::io::Error> for PolicyError {
    fn from(err: std::io::Error) -> Self {
        PolicyError::InternalError(err.to_string())
    }
}

impl From<serde_json::Error> for PolicyError {
    fn from(err: serde_json::Error) -> Self {
        PolicyError::InvalidPolicyContent(err.to_string())
    }
}